package cadtoolbox.graphical;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.collections15.Transformer;

import cadtoolbox.model.OligoGraph;
import cadtoolbox.model.SequenceVertex;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ScalingControl;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.Renderer.VertexLabel.Position;

public class AnimatedSequences {
	
	static OligoGraph<SequenceVertex,String> graph;
	public JFrame myFrame;
	
	public double[][] timeSerie;
	public ArrayList<String> templates;
	public float Fmax;
	public int t = 0;
	public int Tmin = 0;
	public int Tmax;
	public int speed = 100;
	
	public int nVertices = 0;
	public int X=600;
	public int Y=600;
	public double GreyThreshold = 10;	//Threshold beneath which connection is considered inactive (and colored grey)
	public static double RadiusFactor = 1;		//Multiplication factor of the nodes' radiuses
	public static boolean radiusLogScale = true;
	public static boolean showMaxNickSaturation = true;
	public static boolean showMaxPolySaturation = true;
	public static boolean showMaxExoSaturation = true;
	static AnimationOptions op = null;
	public boolean Animate = false;
	public boolean ListenToChange = true;
	public boolean Init = true;
	public boolean Initialized = false;
	
	public JSlider Slider;
	public JTextField TminBox = new JTextField();
	public JTextField TmaxBox = new JTextField();
	public JSlider SpeedBox;
	public JButton AnimBox = new JButton();
	public JButton ResetBox = new JButton();
	public JLabel TimeBox = new JLabel();
	public JButton OptionButton = new JButton("Options");
	
	public int normalSpeed = 200;
	public int maxSpeed = 50;
	
	public VisualizationViewer<SequenceVertex,String> vv;

	public ArrayList<Double> r0 = new ArrayList<Double>();
	public SaturationPanel sat;
	
	
	public AnimatedSequences(double[][] allsequences, double[][] savedActivity, OligoGraph<SequenceVertex,String> graph){
		this.timeSerie = allsequences;
		this.Tmax = allsequences[0].length;
		this.graph = (OligoGraph<SequenceVertex, String>) graph;
		this.myFrame = new JFrame("Animated graph");
		this.templates = new ArrayList<String>(this.graph.getEdges());
		
		OligoISOMLayout layout = new OligoISOMLayout(this.graph);
		layout.setSize(new Dimension(X,Y));
		vv = new VisualizationViewer<SequenceVertex, String>(layout);
		vv.setRenderer(new OligoRenderer<SequenceVertex,String>());
		vv.setBorder(LineBorder.createBlackLineBorder());
		//vv.getRenderContext().setVertexFillPaintTransformer(new MyVertexFillPaintTransformer(this.graph));
		vv.getRenderContext().setVertexFillPaintTransformer(new StabilityVertexFillPaintTransformer<SequenceVertex>(this.graph));
		vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<SequenceVertex>());
		vv.getRenderContext().setEdgeStrokeTransformer(new AnimationEdgeStrokeTransformer<String>(graph));
//		double[][] values = new double[3][this.Tmax];
//		for(int i=0;i<3;i++){
//			for(int j=0;j<Tmax;j++){
//				values[i][j] = Math.random();
//			}
//		}
		this.sat = new SaturationPanel(savedActivity);
		vv.add(sat);
		
		//System.out.println(layout.getSize());
//		VisualizationViewer<SequenceVertex, String> vv = new VisualizationViewer<SequenceVertex, String>(
//				layout);
//		vv.setPreferredSize(new Dimension(300, 300));
//		vv.setBackground(Color.WHITE);
//		// Setup up a new vertex to paint transformer...
//		
//		OligoRenderer<SequenceVertex, String> OligoRen = new OligoRenderer<SequenceVertex, String>();
//		vv.setRenderer(OligoRen);
//		vv.getRenderContext().setVertexFillPaintTransformer(new MyVertexFillPaintTransformer(this.graph));
//		
//		vv.getRenderContext().setVertexLabelTransformer(
//				new ToStringLabeller<SequenceVertex>());
		
		
		
		
		//Initialization radiuses array
		for(int i=0; i<timeSerie.length;i++)
			r0.add(10.0);
		
			ArrayList<String> NodesNames = new ArrayList<String>();
			//Pourquoi tu veux ca bordel???
			for(SequenceVertex seq : graph.getVertices()){
				NodesNames.add(seq.toString());
			}
			nVertices = graph.getVertexCount();
			Fmax = 0;
			for(String conn : graph.getEdges()){
				SequenceVertex From = graph.getEndpoints(conn).getFirst();
				SequenceVertex To = graph.getEndpoints(conn).getSecond();
				
				for(int T = 0; T < timeSerie[0].length; T++){
					double FInh = 0;
					if(graph.getInhibition(conn)!=null){
						SequenceVertex Inh = graph.getInhibition(conn).getLeft();
						
						if(graph.getPlottedSeqs().contains(Inh))
							FInh = timeSerie[findName(Inh)][t] * graph.getK(Inh);
						//else
						//	System.err.println("ERROR! " + Inh.name + " -> " + nameToInt.get(Inh.name));
					}
					double F = 0;
					if(graph.getPlottedSeqs().contains(From))
						F = graph.getTemplateConcentration(conn) * timeSerie[findName(From)][T];
					//else
					//	System.err.println("ERROR! " + conn.from.name + " -> " + nameToInt.get(conn.from.name));
					F = F - FInh > 0 ? F - FInh : 0;
					if(Fmax < F)
						Fmax = (float)F;
				}
			}
			
			
		
		
		
		
		
		// vv.getRenderContext().setEdgeLabelTransformer(new
		// ToStringLabeller());
		vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
		DefaultModalGraphMouse<String, String> gm = new DefaultModalGraphMouse<String, String>();
		gm.setMode(DefaultModalGraphMouse.Mode.PICKING);
		vv.setGraphMouse(gm);
		
		ScalingControl scaler = new CrossoverScalingControl();
		//scaler.scale(vv, (float) 300 / 250, vv.getCenter());
		
		
		
		
///////////////SLIDER DYNAMIC////////////////
		//sliders time
		

		Slider = new JSlider(JSlider.HORIZONTAL, 0, timeSerie[0].length-1, 10);
		//TODO Slider.addChangeListener(this);
		Slider.setMajorTickSpacing(200);
		Slider.setMinorTickSpacing(20);
		Slider.setPaintTicks(true);
		Slider.setPaintLabels(true);
		Slider.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
		Slider.setSize(50, 50);
		Font font = new Font("Serif", Font.ITALIC, 13);
		Slider.setFont(font);
		
		//sliders speed
		SpeedBox = new JSlider(JSlider.HORIZONTAL, 0, normalSpeed+maxSpeed-1, normalSpeed);
		Dimension preferredSize = new Dimension(100, 50);
		SpeedBox.setPreferredSize(preferredSize);
		
		//buttons and labels
		TminBox = new JTextField("0", 3);
		TmaxBox = new JTextField(""+timeSerie[0].length, 3);
		AnimBox = new JButton("Animate");
		AnimBox.setActionCommand("animate");
		AnimBox.addActionListener(new AnimateActionListener());
		ResetBox = new JButton("Disable");
		OptionButton.setActionCommand("options");
		OptionButton.addActionListener(new AnimateActionListener());
		
		//myFrame.add(vv);
		//add to panel layout
		//myFrame.add(Slider);
		JPanel LabelPanel0 = new JPanel();
		TimeBox = new JLabel("   time : " + Slider.getValue());
		LabelPanel0.add(TimeBox);
		//myFrame.add(LabelPanel0);
		
		JPanel LabelPanel1 = new JPanel();
		LabelPanel1.setLayout(new BoxLayout(LabelPanel1, BoxLayout.X_AXIS));
		LabelPanel1.add(new JLabel("               tmin :     "));
		LabelPanel1.add(TminBox);
		LabelPanel1.add(new JLabel("  [0,"+timeSerie[0].length+"]                    "));
		//myFrame.add(LabelPanel1);
		
		JPanel LabelPanel2 = new JPanel();
		LabelPanel2.setLayout(new BoxLayout(LabelPanel2, BoxLayout.X_AXIS));
		LabelPanel2.add(new JLabel("               tmax :    "));
		LabelPanel2.add(TmaxBox);
		LabelPanel2.add(new JLabel("  [1,"+timeSerie[0].length+"]                    "));
		//myFrame.add(LabelPanel2);
		
		JPanel LabelPanel3 = new JPanel();
		LabelPanel3.setLayout(new BoxLayout(LabelPanel3, BoxLayout.X_AXIS));
		LabelPanel3.add(new JLabel("  Speed : "));
		LabelPanel3.add(SpeedBox);
		//myFrame.add(LabelPanel3);
		
		JPanel LabelPanel4 = new JPanel();
		LabelPanel4.setLayout(new BoxLayout(LabelPanel4, BoxLayout.X_AXIS));
		LabelPanel4.add(ResetBox);
		LabelPanel4.add(new JLabel("  "));
		LabelPanel4.add(AnimBox);
		//myFrame.add(LabelPanel4);
		
		
		 javax.swing.GroupLayout nlayout = new javax.swing.GroupLayout(myFrame.getContentPane());
	        myFrame.getContentPane().setLayout(nlayout);
	        nlayout.setHorizontalGroup(
	            nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	            .addGroup(nlayout.createSequentialGroup()
	                .addContainerGap()
	                .addGroup(nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	                    .addComponent(vv, 200, 200, Short.MAX_VALUE)
	                    .addGroup(nlayout.createSequentialGroup()
	                    	.addGroup(nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	                    			.addComponent(Slider, 180, 180, 180)
	                    			.addComponent(LabelPanel3, 180, 180, 180))
	                    	.addGroup(nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	                    			.addComponent(LabelPanel1, 300, 300, javax.swing.GroupLayout.PREFERRED_SIZE)
	                    			.addComponent(LabelPanel2, 300, 300, javax.swing.GroupLayout.PREFERRED_SIZE))
	                        
	                    		.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
	                            .addGroup(nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	                    			.addComponent(AnimBox)
	                    			.addComponent(OptionButton))
	                    		))
	                .addContainerGap())
	        );
	        nlayout.setVerticalGroup(
	            nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	            .addGroup(nlayout.createSequentialGroup()
	                .addContainerGap()
	                .addComponent(vv, 200, 200, Short.MAX_VALUE)
	                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
	                .addGroup(nlayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
	                    .addGroup(nlayout.createSequentialGroup()
	                        .addComponent(Slider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
	                        .addComponent(LabelPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
	                        .addComponent(OptionButton))
	                .addGroup(nlayout.createSequentialGroup()
	                        .addComponent(LabelPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
	                        .addComponent(LabelPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
	                        .addComponent(AnimBox))
	                .addContainerGap())
	        );
		
		/////////////////////////////////////////////
		myFrame.setPreferredSize(new Dimension(X,Y));
		myFrame.pack();
		myFrame.setVisible(true);
		
		//JavaReminder reminderBeep = new JavaReminder(1);
		
		myFrame.addWindowListener(new WindowListener(){

			@Override
			public void windowActivated(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowClosed(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowClosing(WindowEvent arg0) {
				Animate = false;
				myFrame = null;
				
			}

			@Override
			public void windowDeactivated(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowDeiconified(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowIconified(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void windowOpened(WindowEvent arg0) {
				// TODO Auto-generated method stub
				
			}
			
		});
		
	}
	
	/**
	 * The impact on nick depends only on the amount of template in the extended state
	 * For this reason, we return the name of the template with the highest amount of
	 * extended structure. 
	 * @param givenTime
	 * @return
	 */
	public String findMaxNickImpact(int givenTime){
		if(!graph.saturableNick){
			return "";
		}
		int where = graph.getVertexCount();
		double max = 0.0;
		String res = "";
		for(int i = 0; i< this.templates.size(); i++){
			if(max < timeSerie[where+6*i+4][givenTime]){
				max = timeSerie[where+6*i+4][givenTime];
				res = templates.get(i);
			}
		}
		return res;
	}
	
	/**
	 * Similar to nick impact, but a bit trickier.
	 * The impact is based on the quantity of template in the input
	 * or both state, but with different coefficients.
	 * @param givenTime
	 * @return
	 */
	public String findMaxPolyImpact(int givenTime){
		if(!graph.saturablePoly){
			return "";
		}
		int where = graph.getVertexCount();
		double max = 0.0;
		String res = "";
		for(int i = 0; i< this.templates.size(); i++){
			if(max < timeSerie[where+6*i+1][givenTime]/model.Constants.polKm + timeSerie[where+6*i+3][givenTime]/model.Constants.polKmBoth){
				max = timeSerie[where+6*i+1][givenTime]/model.Constants.polKm + timeSerie[where+6*i+3][givenTime]/model.Constants.polKmBoth;
				res = templates.get(i);
			}
		}
		return res;
	}
	
	public SequenceVertex findMaxExoImpact(int givenTime){
		if(!graph.saturableExo){
			return null;
		}
		SequenceVertex res = null;
		double max = 0.0;
		Iterator<SequenceVertex> it = this.graph.getVertices().iterator();
		for(int i=0; i< this.graph.getVertexCount(); i++){
			SequenceVertex s = it.next();
			if(max < timeSerie[i][givenTime]/(graph.isInhibitor(s)?model.Constants.exoKmInhib:model.Constants.exoKmSimple)){
				max = timeSerie[i][givenTime]/(graph.isInhibitor(s)?model.Constants.exoKmInhib:model.Constants.exoKmSimple);
				res = s;
			}
		}
		return res;
	}
	
	public String findMaxExoTemplateImpact(int givenTime){
		if(!(graph.saturableExo && graph.exoSaturationByFreeTemplates)){
			return "";
		}
		int where = graph.getVertexCount();
		double max = timeSerie[findName(findMaxExoImpact(givenTime))][givenTime];
		String res = "";
		for(int i = 0; i< this.templates.size(); i++){
			if(max < timeSerie[where+6*i][givenTime]/model.Constants.polKm/model.Constants.exoKmTemplate){
				max = timeSerie[where+6*i][givenTime]/model.Constants.exoKmTemplate;
				res = templates.get(i);
			}
		}
		return res;
	}
	
	public String[] giveNames() {
	String[] names = new String[graph.getPlottedSeqs().size()];
	int index = 0;
	Iterator<SequenceVertex> it = graph.getPlottedSeqs().iterator();
	while(it.hasNext()){
		names[index] = it.next().toString();
		index++;
	}
	return names;
	}
	
	public int findName(SequenceVertex seq) {
		
		int index = 0;
		Iterator<SequenceVertex> it = graph.getVertices().iterator();
		while(it.hasNext()){
			if(it.next().equals(seq))
				return index;
			index++;
		}
		return -1;
		}
	
class AnimateActionListener implements ActionListener {
		
		public AnimateActionListener() {}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			
			if(!Animate && arg0.getActionCommand().equals("animate")){
				Animate = true;
				JavaReminder reminderBeep = new JavaReminder(1);
				
				AnimBox.setText("   Stop   ");
				
				System.out.println("========== Graph animation activated =============");
			}
			else if(Animate && arg0.getActionCommand().equals("animate")){
				Animate = false;
				AnimBox.setText("Animate");
				System.out.println("========== Graph animation desactivated ==========");
			} else if(arg0.getActionCommand().equals("options")){
				if(AnimatedSequences.op == null){
				AnimatedSequences.op = new AnimationOptions();
				AnimatedSequences.op.setVisible(true);
				}
			}
			
		}
	}
	
	
	
	class ResetActionListener implements ActionListener {
			
		public ResetActionListener() {}

		@Override
		public void actionPerformed(ActionEvent arg0) {
			Animate = false;
			JavaReminder2 reminderBeep = new JavaReminder2(1);
		}
	}

	
	
	class UpdateActionListener implements ChangeListener {
		
		public UpdateActionListener() {}

		@Override
		public void stateChanged(ChangeEvent arg0) {
			if(!Animate && ListenToChange){
				animationGraph();
			}
		}

		
	}
	
	
	
	class DtActionListener implements KeyListener {
		
		public DtActionListener() {}

		@Override
		public void keyReleased(KeyEvent arg0) {
			//Deal with the dialog boxes
			boolean Error = false;
			int tmin = Tmin;
			int tmax = Tmax;
			//if(checkString(displayer.TminBox.get(IndexGen).getText()))
		
			try{
				tmin = Integer.parseInt(TminBox.getText() + "0") / 10;
			} catch (NumberFormatException exp){
				
			}
			//if(checkString(displayer.TmaxBox.get(IndexGen).getText()))
			try{
				tmax = Integer.parseInt(TmaxBox.getText() + "0") / 10;
			} catch (NumberFormatException exp){
				
			}
			if(tmin >= 0 && tmin < timeSerie[0].length){
				if(tmin != Tmin){
					Tmin = tmin;
					ListenToChange = false;
					Slider.setValue(tmin);
					ListenToChange = true;
					Slider.setMinimum(tmin);
				}
			}
			else
				Error = true;
			if(tmax > 0 && tmax <= timeSerie[0].length && tmax > tmin){
				if(tmax != Tmax){
					Tmax = tmax;
					Slider.setMaximum(tmax);
				}
			}
			else
				Error = true;
			double Dt = Slider.getMaximum() - Slider.getMinimum();
			double grad = Dt / 500;
			Slider.setMajorTickSpacing((int)(grad*200));
			Slider.setMinorTickSpacing((int)(grad*20));
			speed = (int)((Dt / 500) * normalSpeed);
			SpeedBox.setValue(speed);
			double Cmax = 0;
			for(int k = Tmin; k < Tmax; k++){
				for(SequenceVertex node : graph.getVertices()){
					if(Cmax < timeSerie[findName(node)][k])
						Cmax = timeSerie[findName(node)][k];
				}
			}
			//((XYPlot) displayer.ExpData.get(IndexGen).Curves.getPlot()).getDomainAxis().setRange(Tmin,Tmax);
			//((XYPlot) displayer.ExpData.get(IndexGen).Curves.getPlot()).getRangeAxis().setRange(0,1.25*Cmax);
			//System.out.println("Tmin = " + Tmin + ", Tmax = " + Tmax + ". Animation speed : " + speed);
			if(Error){
				System.err.println("Interval error!");
				System.err.println("-> tmin : enter integer [0,499]");
				System.err.println("-> tmax : enter integer [1,500]");
				System.err.println("-> tmax > tmin");
			}
		}

		@Override
		public void keyPressed(KeyEvent e) {}

		@Override
		public void keyTyped(KeyEvent e) {}
	}


	
	//for graph animation
	public class JavaReminder {
	    Timer timer;
	    
	    public JavaReminder(int sec) {
	        timer = new Timer();
	        timer.schedule(new RemindTask(), sec*(maxSpeed + (normalSpeed - speed)) );
	    }

	    class RemindTask extends TimerTask {
	        @Override
	        public void run() {
	        	//System.err.println("iteration");
	        	while(Animate){
	            animationGraph();
	            try {
					Thread.sleep(maxSpeed + (normalSpeed - speed));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        	}
	        }
	    }
	}
	
	
	
	//for disabling radiuses and arrows animations
	public class JavaReminder2 {
	    Timer timer;
	    
	    public JavaReminder2(int sec) {
	        timer = new Timer();
	        timer.schedule(new RemindTask(), 2*sec*(maxSpeed + (normalSpeed - speed)) );
	    }

	    class RemindTask extends TimerTask {
	        @Override
	        public void run() {
	            resetGraph();
	        }
	    }
	}
	
	public VisualizationViewer<SequenceVertex, String> animationGraph(){
		
			
			//Edges color
			Transformer<String, Paint> edgePaint = new Transformer<String, Paint>() {
				@Override
				public Paint transform(String i){
					//Button event handler initialization
					if(!Initialized){
						//AnimBox.addActionListener(new AnimateActionListener());
						ResetBox.addActionListener(new ResetActionListener());
						Slider.addChangeListener(new UpdateActionListener());
						TminBox.addKeyListener(new DtActionListener());
						TmaxBox.addKeyListener(new DtActionListener());
						Initialized = true;
					}
					
					//Compute max used templates concentrations for the match
					SequenceVertex From = null;
					SequenceVertex To;
					
					double FInh = 0;
					boolean Cut = false;
					boolean inhib = false;
						if( templates.contains(i) ){
							From = graph.getEndpoints(i).getFirst();
							To = graph.getEndpoints(i).getSecond();
							
							if(graph.getInhibition(i)!=null){
								SequenceVertex Inh = graph.getInhibition(i).getLeft();
								if(graph.getPlottedSeqs().contains(Inh))
									FInh = timeSerie[findName(Inh)][t] * graph.getK(Inh);
							}
						} else if(templates.contains(i.substring(5))){
							
							i = i.substring(5);
							inhib = true;
						}
					
					
					//compute arrows color -> used templates concentrations
					float[] colorVect = {0,0,0};
					//double F = timeSerie[findName(From)][t] * graph.getTemplateConcentration(i);
					//F = F - FInh > 0 ? F - FInh : 0;
					int where = graph.getVertexCount()+6*templates.indexOf(i);
					double F = inhib?timeSerie[where+5][t]:timeSerie[where+1][t] + timeSerie[where+3][t] + timeSerie[where+4][t];
					colorVect[0] = (float)( F / graph.getTemplateConcentration(i) ) * 255;
					colorVect[2] = 255 - (float)( F / graph.getTemplateConcentration(i) ) * 255;
					if(colorVect[0] > 255)
						colorVect[0] = 255;
					if(colorVect[2] < 0)
						colorVect[2] = 0;
					if(colorVect[0] <= GreyThreshold){
						Cut = true;
					}
					//System.err.println("RGB pour " + i + " :    " + (int)colorVect[0] + "," + (int)colorVect[1] + "," + (int)colorVect[2] + ",   t = " + t);
					colorVect = Color.RGBtoHSB((int)colorVect[0], (int)colorVect[1], (int)colorVect[2], colorVect);
					Paint color = Color.getHSBColor(colorVect[0],colorVect[1],colorVect[2]);
					if(Cut)
						color = Color.GRAY;
					return color;
				}
			};
			vv.getRenderContext().setEdgeDrawPaintTransformer(edgePaint);
			vv.getRenderContext().setArrowDrawPaintTransformer(edgePaint);
			vv.getRenderContext().setArrowFillPaintTransformer(edgePaint);
			
			final String maxNick = this.findMaxNickImpact(t);
			final String maxPoly = this.findMaxPolyImpact(t);
			final String maxExo = this.findMaxExoTemplateImpact(t);
			
			vv.getRenderContext().setEdgeLabelTransformer(new Transformer<String,String>(){

				@Override
				public String transform(String arg0) {
					String res = (arg0.equals(maxNick)&&AnimatedSequences.showMaxNickSaturation?"Nick":"");
					if(arg0.equals(maxPoly)&&AnimatedSequences.showMaxPolySaturation){
						res+= (res.length()>0?", ":"")+"Poly";
					}
					if(arg0.equals(maxExo)&&AnimatedSequences.showMaxExoSaturation){
						res+= (res.length()>0?", ":"")+"Exo";
					}
					return res;
				}
			}
			);
			
	
			//Vertexes radius
			Transformer<SequenceVertex, Shape> vertexShape = new Transformer<SequenceVertex, Shape>() {
				ArrayList<SequenceVertex> NodesNames = new ArrayList<SequenceVertex>();
				double r = 10;
				int C = 0;
//				double A = 250*250;
//				double K = Math.pow(1.5*1.5*A/timeSerie.length, 0.5);
				
				@Override
				public Shape transform(SequenceVertex i){
					r = r0.get(findName(i));
					if(timeSerie != null){
						r = 8 + (radiusLogScale?Math.log(1 + 30 * timeSerie[findName(i)][t]):timeSerie[findName(i)][t]) * RadiusFactor;
						if(!NodesNames.contains(i)){
							NodesNames.add(i);
							C++;
						}
						if(C == nVertices ){
							ListenToChange = false;
							Slider.setValue(Slider.getValue() + 1);
							ListenToChange = true;
							t = Slider.getValue();
							sat.setTime(t);
							TimeBox.setText("   time : " + String.valueOf(t));
							speed = SpeedBox.getValue();
							C = 0;
						}
					}
					r0.set(findName(i), r);
					if(t == Tmax-1){
						t = Tmin;
						ListenToChange = false;
						Slider.setValue(t);
						ListenToChange = true;
					}
					
					Shape style = new Ellipse2D.Double(-r,-r,2*r,2*r);
					return(style);
				}
			};
			vv.getRenderContext().setVertexShapeTransformer(vertexShape);
			
//			if(Animate){
//				JavaReminder reminderBeep = new JavaReminder(1);
//			}
		
		
		vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
		vv.repaint();
		ScalingControl scaler = new CrossoverScalingControl();
		
		return vv;
	}
	
	
//Disable animated graph
public VisualizationViewer<SequenceVertex, String> resetGraph(){
			
			//Edges color
			Transformer<String, Paint> edgePaint = new Transformer<String, Paint>() {
				@Override
				public Paint transform(String i){
					return Color.BLACK;
				}
			};
			vv.getRenderContext().setEdgeDrawPaintTransformer(edgePaint);
			vv.getRenderContext().setArrowDrawPaintTransformer(edgePaint);
			vv.getRenderContext().setArrowFillPaintTransformer(edgePaint);
			
	
			//Vertexes radius
			Transformer<SequenceVertex, Shape> vertexShape = new Transformer<SequenceVertex, Shape>() {
				@Override
				public Shape transform(SequenceVertex i){
					Shape style = new Ellipse2D.Double(-10,-10,20,20);
					return(style);
				}
			};
			vv.getRenderContext().setVertexShapeTransformer(vertexShape);
			vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
			ScalingControl scaler = new CrossoverScalingControl();
		
		
		return vv;
	}

}
